/**
 * This class implements the logic behind the BDD for the n-queens problem
 * You should implement all the missing methods
 * 
 * @author Stavros Amanatidis
 *
 */
import java.util.*;

import net.sf.javabdd.*;

public class QueensLogic {
    private int size = 0;
    private int[][] board;
    BDDFactory fact = JFactory.init(2000000,100000);
    BDD T = fact.one();
	BDD F = fact.zero();
	BDD queensBDD[][] = null;
	BDD mainBDD = null;


    public QueensLogic() {
       //constructor
    }

    public void initializeGame(int size) {
        this.size = size;
        this.board = new int[size][size];
		this.fact.setVarNum(size*size);
		this.queensBDD = new BDD[size][size];
		
		
		mainBDD = T;
		
		for (int x = 0; x < size; x++)
			for (int y = 0; y < size; y++)
				queensBDD[x][y] = fact.ithVar(x+size*y);
		

		
//Iterates through all board variables
for (int y = 0; y < size; y++) {
	BDD minQ = fact.zero();
	for (int x = 0; x < size; x++) {
		// Minimum n queens on board, calculated by minimum one queen
		// per row
		minQ.orWith(queensBDD[x][y].id());

		// No queen on same row
		for (int compX = x + 1; compX < size; compX++)
			mainBDD.andWith(
			queensBDD[x][y].imp(queensBDD[compX][y].not()));

		// No queen on same column
		for (int compY = y + 1; compY < size; compY++)
			mainBDD.andWith(
			queensBDD[x][y].imp(queensBDD[x][compY].not()));

		// No queen on same left diagonal
		for (int n = 1; n < size; n++)
			if (n + x < size && n + y < size)
				mainBDD.andWith(
				queensBDD[x][y].imp(queensBDD[n + x][n+y].not()));
		// No queen on same right diagonal
		for (int n = 1; n < size; n++)
			if (x - n >= 0 && y + n < size)
				mainBDD.andWith(
				queensBDD[x][y].imp(queensBDD[x - n][n+y].not()));
	}
	mainBDD.andWith(minQ);
}
    }

   
    public int[][] getGameBoard() {
        return board;
    }

    public boolean insertQueen(int column, int row) {

    	
    	// You cannot put a queen if the space is occupied
        if (board[column][row] == -1 || board[column][row] == 1) {
            return false;
        }
        
// Place the queen
board[column][row] = 1;

// Restrict the mainBDD with a queen on the chosen spot
mainBDD.restrictWith(queensBDD[column][row].id());

// Loop the board and check if a potential queen placement return an
// unsatisfiable mainBDD. In that case block this option.
for (int x = 0; x < this.size; x++) {
	for (int y = 0; y < this.size; y++) {
		if (mainBDD.restrict(this.queensBDD[x][y].id()).isZero())
			board[x][y] = -1;
	}
}

// Loop the board and check if the number of open spaces + the number of
// queens = n.

int counter = 0;
for (int x = 0; x < this.size; x++) {
	for (int y = 0; y < this.size; y++) {
		if (board[x][y] > -1)
			counter++;
	}
}
// In that case place the remaining queens.
if (counter == this.size)
	for (int x = 0; x < this.size; x++) {
		for (int y = 0; y < this.size; y++) {
			if (board[x][y] > -1)
				board[x][y] = 1;
		}
	}


        


        
     
        return true;
    }
}

